/*
 * C3.3.2.c
 *
 *  Created on: 2013/01/17
 *      Author: xun
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rule_info.h"
#include "core.h"
#include "trace.h"
#include "TraceAst.h"

static const PSZ RuleID = "C3.3.2";

//TODO
static const PSZ MESSAGE_ENG = "";
static const PSZ MESSAGE_JPN = "関数プロトタイプ宣言で、識別子が指定されていない仮引数がある。";
static const PSZ MESSAGE_CHS = "";

static const U2 RANK = MSG_RANK_ERR;

static PRULEOUT pRuleHead;
static PRULEOUT pRuleTail;

static INT RuleCheck(U2 kind, AST index, U4 event, AST* pCodeScp);
static INT ParamCheck(AST astindex);

/******************************************************************
 * main logic
 *******************************************************************/
static S4 RuleMain(U2 kind, AST index, U4 event) {
	INT result = RULE_RESULT_OK;
	PRULEOUT newNode = NULL;
	PRULEOUT tmpNode = NULL;
	PRULEOUT tmpNode1 = NULL;

	AST codeScp = 0;

	//TODO
	result = RuleCheck(kind, index, event, &codeScp);

	if (result == RULE_RESULT_OK) {
		return EXIT_SUCCESS;
	}

	/*re-checked?*/
	tmpNode = pRuleHead;
	while (tmpNode != NULL ) {
		if (tmpNode->indexInfo == index) {
			if (result > RULE_RESULT_OK) {
				result = RULE_RESULT_OK;
			} else {
				if (tmpNode == pRuleHead) {
					pRuleHead = pRuleHead->next;
					free(tmpNode);
				} else if (tmpNode == pRuleTail) {
					tmpNode1->next = NULL;
					pRuleTail = tmpNode1;
					free(tmpNode);
				} else {
					tmpNode1->next = tmpNode->next;
					free(tmpNode);
				}
			}
			break;
		}
		tmpNode1 = tmpNode;
		tmpNode = tmpNode->next;
	}

	/*make result struct*/
	if (result > RULE_RESULT_OK) {
		newNode = (PRULEOUT) malloc(sizeof(RULEOUT));
		if (pRuleHead == NULL ) {
			pRuleHead = newNode;
		}

		//TODO
		//codeScp = ??;
		newNode->indexInfo = index;
		newNode->fileIndex = CCodeScope.getFileIndex(codeScp);
		newNode->beginLine = CCodeScope.getBeginLine(codeScp);
		newNode->beginCol = CCodeScope.getBeginLineOffset(codeScp);
		newNode->endLine = CCodeScope.getEndLine(codeScp);
		newNode->endCol = CCodeScope.getEndLineOffset(codeScp);
		newNode->ruleID = RuleID;
		newNode->errRank = RANK;

		//TODO
		sprintf(newNode->msgBuf_eng, MESSAGE_ENG);
		sprintf(newNode->msgBuf_chs, MESSAGE_CHS);
		sprintf(newNode->msgBuf_jpn, MESSAGE_JPN);

		newNode->rfileIndex = 0;
		newNode->rlocLine = 0;
		newNode->next = NULL;

		if (pRuleTail != NULL ) {
			pRuleTail->next = newNode;
		}

		pRuleTail = newNode;
	}

	return EXIT_SUCCESS;
}

VOID C3_3_2_register(VOID) {
	PRULEMAN * pCurRule = &stRuleManager;
	PRULEMAN newRuleMan = (PRULEMAN) malloc(sizeof(RULEMAN));
	memset(newRuleMan, 0, sizeof(RULEMAN));
	newRuleMan->ruleID = RuleID;
	newRuleMan->ruleSwitch = OFF;
	newRuleMan->headOut = &pRuleHead;
	newRuleMan->tailOut = &pRuleTail;
	newRuleMan->ruleMain_ast = RuleMain;
	if (stRuleManager == NULL ) {
		stRuleManager = newRuleMan;
	} else {
		while ((*pCurRule)->nextRule != NULL ) {
			pCurRule = &((*pCurRule)->nextRule);
		}
		(*pCurRule)->nextRule = newRuleMan;
	}
}

static INT RuleCheck(U2 kind, AST index, U4 event, AST* pCodeScp) {
	INT result = RULE_RESULT_OK;

	AST astDeclarator = 0;
	AST astParamDecl = 0;
	AST astTypeSpec = 0;

	if (kind != TR_KIND_DECLARATION) {
		return EXIT_SUCCESS;
	}

	if (!(event & EVT_DECLARATION)) {
		return EXIT_SUCCESS;
	}

	astDeclarator = CDeclaration.getDeclarator(index);
	if (astDeclarator != 0 && CDeclarator.isFunctionDeclarator(astDeclarator)) {
		astParamDecl = CDeclarator.function_getParamChain(astDeclarator);
		if (astParamDecl != 0 && CDeclaration.isParameter(astParamDecl)) {
			//if there is only one declaration with no declarator and type is void , return OK
			if (CDeclaration.getNextDeclaration(astParamDecl) == 0
					&& CDeclaration.getDeclarator(astParamDecl) == 0) {
				astTypeSpec = CDeclaration.getTypeSpecifier(astParamDecl);
				if (astTypeSpec != 0
						&& CTypeSpecifier.isBasicType(astTypeSpec)) {
					//if type is "void" return OK
					if (CTypeSpecifier.getTypeInfo(astTypeSpec) == 1) {
						return RULE_RESULT_OK;
					}
				}
			}

			while (astParamDecl != 0) {
				if (ParamCheck(astParamDecl) == RULE_RESULT_NG) {
					*pCodeScp = CDeclaration.getCodeScope(astParamDecl);
					return RULE_RESULT_NG;
				}
				astParamDecl = CDeclaration.getNextDeclaration(astParamDecl);
			}

		}
	}

	return result;

}

static INT ParamCheck(AST astindex) {
	INT result = RULE_RESULT_OK;

	AST astDeclarator = 0;
	AST astSymbol = 0;

	astDeclarator = CDeclaration.getDeclarator(astindex);
	if (astDeclarator == 0) {
		return RULE_RESULT_NG;
	}

	if (CDeclarator.isSymbolDeclarator(astDeclarator)) {
		astSymbol = CDeclarator.symbol_getSymbol(astDeclarator);
		if (astSymbol == 0) {
			return RULE_RESULT_NG;
		}
	} else if (CDeclarator.isPointerDeclarator(astDeclarator)
			|| CDeclarator.isParentheseDeclarator(astDeclarator)
			|| CDeclarator.isInitialExpDeclarator(astDeclarator)
			|| CDeclarator.isFunctionDeclarator(astDeclarator)
			|| CDeclarator.isBitfieldDeclarator(astDeclarator)
			|| CDeclarator.isArrayDeclarator(astDeclarator)) {
		astDeclarator = CDeclarator.getChildDeclarator(astDeclarator);
		return ParamCheck(astDeclarator);
	}

	return result;

}
